<?php

/**************************************************************************************************************************
 *                                                      === XERO ===                                                      *
 *                                                  hello.xero@gmail.com                                                  *
 * We provide a FREE software consultancy and development service to ensure that your ideas will be realized.             *
 * Gurus in C++ / C / (ARM, Z80, Intel, 68K) Assembler / LISP / LUA / Smalltalk / PHP / Java / Symbian / Windows /        *
 * Linux / Kernels / Architecture / API design / Penetration / Protection / Graphics / Audio                              *
 **************************************************************************************************************************/


/**
 * Multilingual blog.
 * @author XERO
 */


require_once('bootstrap.php');


try {
    main();
} catch (Exception $e) {
    echo $e;
    die();
}


function main()
{
    // Assign variables to view for use in the HTML view template.
    $view = &$GLOBALS['view'];

    // Merge input the $_POST array will overwrite any duplicate keys in the $_GET array.
    // This is used only to merge data that may be sent by either http post or get.
    $input = multiMerge($_GET, $_POST);

    // Get article id. Default to first article id.
    $articleId = 1;
    if (array_key_exists('article', $input)) {
        $articleId = intval($input['article'], 10);
    }

    // Get ISO language code. Default is no language.
    $langId = null;
    if (array_key_exists('lang', $input)) {
        if (preg_match('#^[a-z]{2}$#', $input['lang'])) {
            $langId = $input['lang'];
        }
    }

    // Initialize the PDO database object.
    $db = initDb();

    // Try to fetch the article.
    $view['article'] = fetchArticle($db, $articleId);
    $view['article_exists'] = !empty($view['article']);
    $view['article']['id'] = $articleId;

    // Update databaase with a new comment that was sent by posting a form to this page.
    $record = array_intersect_key($_POST, array('comment' => null, 'name' => null, 'email' => null));
    addComment($db, $articleId, $langId, $record);

    $language = fetchLanguageName($db, $langId);
    if (array_key_exists('english_name', $language)) {
        // Language code was recognised.
        $view['lang_name'] = $language['english_name'];
        $view['lang_id'] = $langId;
    }

    $view['comments'] = isset($langId) ? hashByFields(fetchComments($db, $articleId, $langId), 'id') : array();
    $view['comments_exist'] = count($view['comments']) > 0;

    // Attributes for HTML <select> element.
        $name = 'comment_languages';
        $attrs = array(
            'id' => &$name,
            'name' => 'lang'
        );

        // Get the languages that the comments have already been written in.
        $commentLanguages = hashByFields(fetchLanguages($db, $articleId), 'id');
        $selectCommentLanguages = new SelectElement($attrs, $commentLanguages, $langId);
        // Build XHTML <select> element and assign it to the view.
        $view['select_comment_languages'] = $selectCommentLanguages->__toString();
        unset($selectCommentLanguages);

        $name = 'remaining_languages';
        // Get the remaining languages that comments have not been written in.
        $remainingLanguages = array_diff_key(hashByFields(fetchLanguages($db), 'id'), $commentLanguages);
        $selectRemainingLanguages = new SelectElement($attrs, $remainingLanguages, $langId);
        // Build XHTML <select> element and assign it to the view.
        $view['select_remaining_languages'] = $selectRemainingLanguages->__toString();
        unset($selectRemainingLanguages);

        // Cleanup PDO database object.
        unset($db);
    }


    /**
     * Fetch languages from the database.
     *
     * @param object $aDb Database
     * @param integer $aArticleId Article id
     * @return array
     */
    function fetchLanguages($aDb, $aArticleId = null)
    {
        $queryStr = 'SELECT language.id AS id, language.native_name AS native_name ' .
                    'FROM languages AS language';
        if (isset($aArticleId)) {
            $queryStr .= ' INNER JOIN comments AS comment ON comment.language_id = language.id' .
                         ' WHERE comment.article_id = :article_id';
        }
        $queryStr .= ' ORDER BY native_name';

        $stmt = $aDb->prepare($queryStr);
        if (isset($aArticleId)) {
            $stmt->bindValue(":article_id", $aArticleId, PDO::PARAM_INT);
        }
        $stmt->execute();
        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
        if (false === $result) {
            $result = array();
        }
        return $result;
    }


    /**
     * Fetch a language name from the database.
     *
     * @param object $aDb Database
     * @param string $aLangId Language id
     * @return array Contains two keys: 'native_name' and 'english _name'
     */
    function fetchLanguageName($aDb, $aLangId)
    {
        $queryStr = 'SELECT native_name, english_name ' .
                    'FROM languages ' .
                    'WHERE id = :lang_id';

        $stmt = $aDb->prepare($queryStr);
        $stmt->bindValue(':lang_id', $aLangId, PDO::PARAM_STR);
        $stmt->execute();

        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        if (false === $result) {
            $result = array();
        }
        return $result;
    }


    /**
     * Fetch an article from the database.
     *
     * @param object $aDb Database
     * @param integer $aId Article id
     * @return array
     */
    function fetchArticle($aDb, $aId)
    {
        $stmt = $aDb->prepare('SELECT title AS title, data AS data, UNIX_TIMESTAMP(created_on) AS created_on FROM articles WHERE id = :id');
        $stmt->bindValue(":id", $aId, PDO::PARAM_INT);
        $stmt->execute();
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        if (false === $result) {
            $result = array();
        }
        return $result;
    }


    /**
     * Fetch the comments on an article from the database
     *
     * @param object $aDb Database
     * @param integer $aArticleId Article id
     * @param string $aLangId The ISO language code.
     * @return array
     */
    function fetchComments($aDb, $aArticleId, $aLangId = null)
    {
        $queryStr = 'SELECT comment.id AS id, comment.name AS name, comment.email AS email, ' .
                    'comment.data AS data, UNIX_TIMESTAMP(comment.created_on) AS created_on ' .
                    'FROM comments AS comment ' .
                    'WHERE comment.article_id = :article_id';
        if (isset($aLangId)) {
            $queryStr .= ' AND comment.language_id = :lang_id';
        }

        $stmt = $aDb->prepare($queryStr);
        $stmt->bindValue(":article_id", $aArticleId, PDO::PARAM_INT);
        if (isset($aLangId)) {
            $stmt->bindValue(":lang_id", $aLangId, PDO::PARAM_STR);
        }
        $stmt->execute();
        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
        if (false === $result) {
            $result = array();
        }
        return $result;
    }


    /**
     * Add a comment to the database.
     *
     * @param object $aDb Database
     * @param integer $aArticle
     * @param string $aLangId
     * @param array $aRecord
     * @throws Exception
     */
    function addComment($aDb, $aArticle, $aLangId, array $aRecord)
    {
        if (is_int($aArticle) && !empty($aLangId) &&
            !empty($aRecord['name']) && !empty($aRecord['email']) && !empty($aRecord['comment'])) {

            $stmt = $aDb->prepare(
                'INSERT INTO comments (article_id, language_id, name, email, data) ' .
                'VALUES (:article_id, :lang_id, :name, :email, :comment)'
            );
            $stmt->bindValue(':article_id', $aArticle);
            $stmt->bindValue(':lang_id', $aLangId);
            $stmt->bindValue(':name', escape($aRecord['name']));
            $stmt->bindValue(':email', escape($aRecord['email']));
            $stmt->bindValue(':comment', escape($aRecord['comment']));

            if (false === $stmt->execute()) {
                throw new Exception('Unable to add comment');
            }
        }
    }
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>
            Lingo Blog test page.
        </title>
        <meta http-equiv = "Content-Type" content = "text/html;charset=UTF-8" />
        <link rel = "stylesheet" href = "/all.css" type = "text/css" media = "screen" />
    </head>
    <body>
        <div id = "article">
            <?if ($view['article_exists']):?>
                <h2>
                    <?=date('l jS F Y', $view['article']['created_on']);?>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<?=$view['article']['title'];?>
                </h2>
                <p>
                    <?=$view['article']['data'];?>
                </p>
                <?if (!empty($view['select_comment_languages'])):?>
                    <hr />
                    <form action = "index.php" method = "get">
                        <p>
                            <input type = "hidden" name = "article" value = "<?=$view['article']['id'];?>" />
                            <label for = "comment_languages">View comments in</label>
                            <?=$view['select_comment_languages'];?>
                            &nbsp;
                            <input type = "submit" value = "Show" />
                        </p>
                    </form>
                <?endif;?>
                <?if ($view['comments_exist']):?>
                    <!-- List comments -->
                    <ol>
                        <?foreach ($view['comments'] as $comment) {?>
                            <li>
                                <p>
                                    <i>
                                        <?=$comment['name'];?>&nbsp;on&nbsp;<?=date('l jS F Y \a\\t g:ia', intval($comment['created_on'], 10));?>
                                    </i>
                                    <br />
                                    <?=$comment['data'];?>
                                </p>
                            </li>
                        <?};?>
                    </ol>
                <?endif;?>
                <?if (isset($view['lang_id']) || !empty($view['select_remaining_languages'])):?>
                    <hr />
                    <p>
                        Please reply in <?=isset($view['lang_name']) ? $view['lang_name'] : 'your chosen language';?>
                    </p>
                    <form action = "index.php" method = "post">
                        <p>
                            <input type = "hidden" name = "article" value = "<?=$view['article']['id'];?>" />
                            <?if (isset($view['lang_id'])):?>
                                <input type = "hidden" name = "lang" value = "<?=$view['lang_id'];?>" />
                            <?else:?>
                                <label for = "remaining_languages">language</label>
                                <?=$view['select_remaining_languages'];?>
                            <?endif;?>
                        </p>
                        <p>
                            <label for = "name">name</label>
                            <input type = "text" id = "name" name = "name" maxlength = "80" tabindex = "1" />
                        </p>
                        <p>
                            <label for = "email">email</label>
                            <input type = "text" id = "email" name = "email" maxlength = "80" tabindex = "2" />
                        </p>
                        <p>
                            <textarea name = "comment" rows = "8" cols = "80" tabindex = "3"></textarea>
                        </p>
                        <p>
                            <input type = "submit" value = "Reply" />
                        </p>
                    </form>
                <?endif;?>
            <?else:?>
                <p class = "center">
                    The article you requested could not be found.
                </p>
            <?endif;?>
        </div>
    </body>
</html>
